/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bff.designtime.generator.core.rtgen.managergenerator.mgrImplclass.propertygenerators;

import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.bff.api.attribute.AbstractSourceConfig;
import com.inspur.edp.bff.api.manager.SourceConfig;
import com.inspur.edp.bff.api.manager.SourceType;
import com.inspur.edp.bff.designtime.generator.core.rtgen.managergenerator.mgrImplclass.FSMgrImplGenContext;
import com.inspur.edp.bff.spi.BffSourceConfig;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.property.ClassPropertyGenerator;
import com.inspur.edp.caf.generator.utils.ExpressionUtils;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import lombok.var;
import org.eclipse.jdt.core.dom.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;

public class SourceConfigPropGenerator extends ClassPropertyGenerator {

    private static final String beType = "GSPBusinessEntity";
    private static final String qoType = "QueryObject";
    private FSMgrImplGenContext mgrImplGenContext;
    private ArrayList<SourceConfig> sourceConfigs = new ArrayList<>();


    public SourceConfigPropGenerator(FSMgrImplGenContext mgrImplGenContext) {
        this.mgrImplGenContext = mgrImplGenContext;
        initSourceConfigs();
    }

    @Override
    protected ArrayList<Modifier.ModifierKeyword> getGetterAccessModifier() {
        return new ArrayList(Arrays.asList(new Modifier.ModifierKeyword[]{
                Modifier.ModifierKeyword.PUBLIC_KEYWORD
        }));
    }

    @Override
    protected ArrayList<Modifier.ModifierKeyword> getSetterAccessModifier() {
        return null;
    }

    @Override
    protected boolean isGetterOverride() {
        return true;
    }

    @Override
    protected TypeInfo getPropertyType() {
        return new TypeInfo(AbstractSourceConfig.class);
    }

    @Override
    protected String getPropertyName() {
        return "SourceConfigs";
    }

    @Override
    protected Block buildGetMethodBody() {

        String configName = "config";
        String itemName = "item";
        var block = ast.newBlock();
        addCreateConfigStatement(block, configName);
        buildSetConfigStatements(block, configName, itemName);
        addReturnStatement(block, configName);
        return block;
    }

    //region method body

    private void addCreateConfigStatement(Block block, String valName){
        TypeInfo info = new TypeInfo(BffSourceConfig.class);
        var creation = ast.newClassInstanceCreation();
        creation.setType(info.getType(ast, mgrImplGenContext.getMgrGenContext().getFSGeneratorContext()));

        VariableDeclarationFragment fragment = ast.newVariableDeclarationFragment();
        fragment.setInitializer(creation);
        fragment.setName(ast.newSimpleName(valName));

        VariableDeclarationStatement statement =ast.newVariableDeclarationStatement(fragment);
        statement.setType(info.getType(ast, mgrImplGenContext.getMgrGenContext().getFSGeneratorContext()));

        block.statements().add(statement);
    }

    private void buildSetConfigStatements(Block block, String varName, String itemName){
        addInitStatement(block, itemName);
        addSetSourceConfigStatements(block, varName, itemName);
    }

    private void addInitStatement(Block block, String itemName) {
        VariableDeclarationFragment variableDeclarationFragment=ast.newVariableDeclarationFragment();
        variableDeclarationFragment.setName(ast.newSimpleName(itemName));
        variableDeclarationFragment.setInitializer(ast.newNullLiteral());
        VariableDeclarationStatement variableDeclarationStatement=ast.newVariableDeclarationStatement(variableDeclarationFragment);
        variableDeclarationStatement.setType(new TypeInfo(SourceConfig.class).getType(ast, mgrImplGenContext.getMgrGenContext().getFSGeneratorContext()));
        block.statements().add(variableDeclarationStatement);
    }

    private void addSetSourceConfigStatements(Block block, String varName, String itemName) {
        if (sourceConfigs.size() == 0)
            return;
        for (SourceConfig sourceConfig : sourceConfigs) {
            addNewItemStatement(sourceConfig, block, itemName);
            addSetIdStatement(sourceConfig, block, itemName);
            addSetTypeStatement(block, itemName);
            addConfigStatement(block, varName, itemName);
        }
    }

    private void addNewItemStatement(SourceConfig sourceConfig, Block block, String itemName) {
        Assignment assignment=ast.newAssignment();
        assignment.setLeftHandSide(ast.newSimpleName(itemName));
        assignment.setOperator(Assignment.Operator.ASSIGN);
        ClassInstanceCreation classInstanceCreation=ast.newClassInstanceCreation();
        classInstanceCreation.setType(new TypeInfo(SourceConfig.class).getType(ast, mgrImplGenContext.getMgrGenContext().getFSGeneratorContext()));
        assignment.setRightHandSide(classInstanceCreation);

        block.statements().add(ast.newExpressionStatement(assignment));
    }

    private void addSetIdStatement(SourceConfig sourceConfig, Block block, String itemName) {
        MethodInvocation methodInvocation=ast.newMethodInvocation();
        methodInvocation.setExpression(ast.newSimpleName(itemName));
        methodInvocation.setName(ast.newSimpleName("setSourceConfigId"));
        StringLiteral stringLiteral=ast.newStringLiteral();
        stringLiteral.setLiteralValue(sourceConfig.getSourceConfigId());
        methodInvocation.arguments().add(stringLiteral);
        block.statements().add(ast.newExpressionStatement(methodInvocation));
    }

    private void addSetTypeStatement(Block block, String itemName) {
        MethodInvocation methodInvocation=ast.newMethodInvocation();
        methodInvocation.setExpression(ast.newSimpleName(itemName));
        methodInvocation.setName(ast.newSimpleName("setSourceType"));
        methodInvocation.arguments().add(ast.newQualifiedName(ast.newName(SourceType.class.getTypeName()),ast.newSimpleName("Be")));

        block.statements().add(ast.newExpressionStatement(methodInvocation));
    }

    private void addConfigStatement(Block block, String varName, String itemName) {
        MethodInvocation methodInvocation = ExpressionUtils.getMethodInvocation(ast, varName, "addConfig");
        methodInvocation.arguments().add(ast.newSimpleName(itemName));
        block.statements().add(ast.newExpressionStatement(methodInvocation));
    }

    private void addReturnStatement(Block block, String varName){
        var returnStatement = ast.newReturnStatement();
        returnStatement.setExpression(ast.newSimpleName(varName));
        block.statements().add(returnStatement);
    }
    //endregion

    @Override
    protected boolean hasSetMethod() {
        return false;
    }

    private void initSourceConfigs() {
        LinkedHashMap<String, GspMetadata> entities = mgrImplGenContext.getMgrGenContext().getFSGeneratorContext().getVmGenContext()
                .getRefEntityCollection();
        if (entities != null && entities.size() > 0) {
            for (Map.Entry<String, GspMetadata> entity : entities.entrySet()) {
                switch (entity.getValue().getHeader().getType()) {
                    case beType:
                        sourceConfigs.add(getBeSourceConfig(entity.getValue()));
                        break;
                    //Java版临时注释：QO
//          case qoType:
//            sourceConfigs.add(GetQoSourceConfig(entity.getValue()));
//            break;
                    default:
                        throw new RuntimeException("无效的元数据类型{"+entity.getValue().getHeader().getType()+"}");
                }
            }
        }
    }

    private SourceConfig getBeSourceConfig(GspMetadata metadata) {
        SourceConfig tempVar = new SourceConfig();
        tempVar.setSourceConfigId (((GspBusinessEntity) metadata.getContent()).getGeneratedConfigID());
        tempVar.setSourceType(com.inspur.edp.bff.api.manager.SourceType.Be);
        SourceConfig sourceConfig = tempVar;
        return sourceConfig;
    }


}
